package znet

import (
	"fmt"
	"net"
	"time"
	"errors"
	"zinx/ziface"
	"zinx/utils"
)

type Server struct {
	Name string
	IPVersion string
	IP string
	Port int
	Router ziface.IRouter
}

func CallBackToClient(conn *net.TCPConn, data []byte, cnt int) error {
	fmt.Println("[Conn Handle] CallBackToClient")
	if _, err := conn.Write(data[:cnt]); err != nil {
		fmt.Println("Write back buf err ",err)
		return errors.New("CallbackToClient error")
	}
	return nil
}

func(s *Server) Start() {
	fmt.Printf("[START] Server listener at : IP : %s, Port %d, is starting\n",s.IP,s.Port)	
	go func() {
		addr,err := net.ResolveTCPAddr(s.IPVersion,fmt.Sprintf("%s:%d",s.IP,s.Port))
		if err != nil {
			fmt.Println("resolve tcp addr err: ",err)
			return
		}

		listener,err := net.ListenTCP(s.IPVersion,addr)
		if err != nil {
			fmt.Println("listen",s.IPVersion,"err",err)
			return
		}
		fmt.Println("start Zinx server ",s.Name," succ,now listening")

		var cid uint32
		cid = 0

		//3 启动server 网络连接业务
		for {
			conn,err := listener.AcceptTCP()
			if err != nil {
				fmt.Println("Accept err ",err)
				continue
			}

			/*
			go func() {
				for {
					buf := make([]byte,512)
					cnt,err := conn.Read(buf)
					if err != nil {
						fmt.Println("recv buf err ",err)
						continue
					}
					if _,err := conn.Write(buf[:cnt]); err != nil {
						fmt.Println("write back buf err ",err)
						continue
					}
				}
			}()
			*/
			//dealConn := NewConnection(conn,cid,CallBackToClient)
			dealConn := NewConnection(conn,cid,s.Router)
			cid ++

			go dealConn.Start()
		}
	}()
}

func (s* Server) Stop() {
	fmt.Println("[STOP] Zinx server, name ",s.Name)
}

func (s* Server) Serve() {
	s.Start()

	for {
		time.Sleep(10 * time.Second)
	}
}

func (s *Server)AddRouter(router ziface.IRouter) {
	s.Router = router
	fmt.Println("addRouter succ! ")
}

func NewServer () ziface.IServer {
	
	utils.GlobalObject.Reload()

	s := &Server {
		Name :utils.GlobalObject.Name,
		IPVersion:"tcp4",
		IP:utils.GlobalObject.Host,
		Port:utils.GlobalObject.TcpPort,
		Router : nil,
	}
	return s
}

